import optuna
import xgboost as xgb
from optuna.samplers import TPESampler
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import VotingClassifier
from sklearn.metrics import accuracy_score
import joblib
from data_processing import data_processing

# 数据导入+特征提取
d1 = data_processing('../data/raw/train.csv', '../data/raw/test2.csv')
X_train, y_train, X_test, y_test = d1[0], d1[1], d1[2], d1[3]


"""
构建一个融合 XGBoost（梯度提升树）与逻辑回归的软投票集成模型，并通过 Optuna 工具的 TPE 采样算法，
对模型超参数进行多轮优化，最终提升模型在二分类任务中的预测准确率。
代码整体分为 “集成模型定义”“超参数优化目标函数”“优化执行” 三大核心模块
__init__方法:初始化基模型与集成模型,
1. 参数默认值设置;
2.集成逻辑:通过VotingClassifier构建软投票集成，voting='soft'表示基于基模型的预测概率加权投票
软投票集成策略允许每个基模型输出概率预测，然后对这些概率进行加权平均，最终根据平均概率做出分类决策。(群里对软投票集成有图文解释）
"""
# 使用sklearn的VotingClassifier简化集成
class SimplifiedEnsemble:
    def __init__(self, xgb_params=None, lr_params=None):
        if xgb_params is None:
            xgb_params = {
                'objective': 'binary:logistic',
                'eval_metric': 'logloss',
                'random_state': 42
            }

        if lr_params is None:
            lr_params = {'random_state': 42, 'max_iter': 100000, 'C': 10.0, 'solver': 'newton-cg'}

        # 初始化XGBoost分类器模型，使用传入的参数配置
        self.xgb_model = xgb.XGBClassifier(**xgb_params)

        # 初始化逻辑回归分类器模型，使用传入的参数配置
        self.lr_model = LogisticRegression(**lr_params)

        # 构建投票集成分类器，将XGBoost和逻辑回归模型进行软投票集成
        # estimators: 包含多个基分类器的列表，每个元素为(名称, 分类器实例)的元组
        # voting: 投票方式，'soft'表示使用预测概率进行加权投票
        self.ensemble = VotingClassifier(
            estimators=[
                ('xgb', self.xgb_model),
                ('lr', self.lr_model)
            ],
            voting='soft'
        )
    """
训练集成模型
直接调用ensemble.fit(X, y)，底层会同步训练两个基模型并完成集成逻辑，
输入为特征矩阵X和标签y，返回训练后的模型实例。
    """

    def fit(self, X, y):
        self.ensemble.fit(X, y)
        return self

    """
调用ensemble.predict(X)
基于软投票结果输出最终类别（0 或 1），适用于直接获取分类结论的场景。
"""

    def predict(self, X):
        return self.ensemble.predict(X)

    """
    调用ensemble.predict_proba(X)，
    输出每个样本属于类别 0 和类别 1 的概率（总和为 1），
    适用于需要概率置信度的场景（如风控中的风险评分）。
    """

    def predict_proba(self, X):
        return self.ensemble.predict_proba(X)



"""
该函数是 Optuna 优化的 “核心任务”，定义了 “超参数搜索空间” 与 “优化指标”，每一次超参数组合的验证都通过该函数执行。
优化逻辑
输入：Optuna 的trial对象（用于获取本次试验的超参数组合）；
流程：初始化SimplifiedEnsemble→训练模型→测试集预测→计算准确率；
输出：测试集准确率（Optuna 以 “最大化该值” 为目标）
"""
# # 简化的目标函数
# def objective_ensemble(trial):
#     xgb_param = {
#         'reg_alpha': trial.suggest_float('reg_alpha', 1e-8, 10.0, log=True),
#         'reg_lambda': trial.suggest_float('reg_lambda', 1e-8, 10.0, log=True),
#         'learning_rate': trial.suggest_float('learning_rate', 1e-4, 0.5, log=True),
#         'n_estimators': trial.suggest_int('n_estimators', 1, 500),
#         'subsample': trial.suggest_float('subsample', 0.6, 1.0),
#         'colsample_bytree': trial.suggest_float('colsample_bytree', 0.6, 1.0),
#         'random_state': trial.suggest_int('random_state', 0, 999)
#         # 固定种子     'early_stopping_rounds': 50  # 新增早停参数
#     }
#
#     model = SimplifiedEnsemble(xgb_params=xgb_param)
#     model.fit(X_train, y_train)
#     y_pred = model.predict(X_test)
#     return accuracy_score(y_test, y_pred)
#
#
# # 优化过程
# sampler_ensemble = TPESampler(seed=50)
# study_ensemble = optuna.create_study(direction='maximize', sampler=sampler_ensemble)
# print("开始超参数优化...")
# study_ensemble.optimize(objective_ensemble, n_trials=2000)  # 减少试验次数以加快速度
#
# # 输出结果
# print("最佳准确率: {:.4f}".format(study_ensemble.best_value))
# print("最佳参数:", study_ensemble.best_params)
#
# joblib.dump(study_ensemble,'../model/魔杰大模型.pkl',)
# print('模型保存成功')